package com.hui.stock.security.config;

import com.hui.stock.security.filter.JwtAuthorizationFilter;
import com.hui.stock.security.filter.JwtLoginAuthenticationFilter;
import com.hui.stock.security.handler.StockAccessDenyHandler;
import com.hui.stock.security.handler.StockAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author: ymh
 * @date: 2025/1/8 9:05
 * @description:
 */
@Configuration
@EnableWebSecurity//开启web安全设置生效
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启对SpringSecurity注解功能的支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 定义公共的无需被拦截的资源
     * @return
     */
    private String[] getPubPath(){
        //公共访问资源
        String[] urls = {
                "/**/*.css","/**/*.js","/favicon.ico","/doc.html",
                "/druid/**","/webjars/**","/v2/api-docs","/api/captcha",
                "/swagger/**","/swagger-resources/**","/swagger-ui.html"
        };
        return urls;
    }

    /**
     * 配置资源权限绑定配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登出功能
        http.logout().logoutUrl("/api/logout").invalidateHttpSession(true);
        //开启允许iframe 嵌套。security默认禁用ifram跨域与缓存
        http.headers().frameOptions().disable().cacheControl().disable();
        //session禁用
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();//禁用跨站请求伪造
        http.authorizeRequests()//对资源进行认证处理
                .antMatchers(getPubPath()).permitAll()//公共资源都允许访问
                .anyRequest().authenticated();  //除了上述资源外，其它资源，只有 认证通过后，才能有权访问

        //将自定义的认证过滤器加入security过滤器链，且在默认的认证过滤器之前执行
        http.addFilterBefore(jwtLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        //配置授权过滤器，过滤一切资源，是资源安全的屏障，优先级最高，所以需要在认证的过滤器之前
        //对于每个请求，都需要判断是否有权限去访问，所以需要先进行授权过滤，如果票据过期或者其他，则重新进行认证登录，如果通过，则进入下一个过滤器
        http.addFilterBefore(jwtAuthorizationFilter(), JwtLoginAuthenticationFilter.class);
        http.exceptionHandling().accessDeniedHandler(new StockAccessDenyHandler())
                                .authenticationEntryPoint(new StockAuthenticationEntryPoint());
    }

    /**
     * 定义认证过滤器
     * @return
     * @throws Exception
     */
    @Bean
    public JwtLoginAuthenticationFilter jwtLoginAuthenticationFilter() throws Exception {
        JwtLoginAuthenticationFilter authenticationFilter = new JwtLoginAuthenticationFilter("/api/login");
        authenticationFilter.setAuthenticationManager(authenticationManagerBean());
        //注入redis模板对象
        authenticationFilter.setRedisTemplate(redisTemplate);
        return authenticationFilter;
    }

    /**
     * 定义授权过滤器
     * 负责检查jwt的票据是否有效，做相关处理
     * @return
     */
    @Bean
    public JwtAuthorizationFilter jwtAuthorizationFilter(){
        return new JwtAuthorizationFilter();
    }

    /**
     * 密码加密器
     *   BCryptPasswordEncoder方法采用SHA-256对密码进行加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 维护授权过滤器bean
     * 负责检查jwt的票据是否有效，做相关处理
     * @return
     */
    // @Bean
    // public AuthenticationFilter authenticationFilter(){
    //     AuthenticationFilter authenticationFilter = new AuthenticationFilter();
    //     return authenticationFilter;
    // }
}
